<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Plugins\Protos;

use Google\Protobuf\ListValue;
use Google\Protobuf\NullValue;
use Google\Protobuf\Struct;
use Google\Protobuf\Value;
use Srv\Libs\Common\CommValid;

class ProtoValue
{
    /**
     * @param string $str
     * @return Value
     * genStringValue
     */
    public static function genStringValue(string $str):Value
    {
        $Value                  = new Value();
        $Value->setStringValue($str);
        return $Value;
    }

    /**
     * @param int $num
     * @return Value
     * genNumberIntValue
     */
    public static function genNumberIntValue(int $num):Value
    {
        $Value                  = new Value();
        $Value->setNumberValue($num);
        return $Value;
    }

    /**
     * @param float $float
     * @return Value
     * genNumberFloatValue
     */
    public static function genNumberFloatValue(float $float):Value
    {
        $Value                  = new Value();
        $Value->setNumberValue($float);
        return $Value;
    }

    /**
     * @param string $numStr
     * @return Value
     * genNumberStrValue
     */
    public static function genNumberStrValue(string $numStr):Value
    {
        $Value                  = new Value();
        $Value->setNumberValue($numStr);
        return $Value;
    }

    /**
     * @param bool $bool
     * @return Value
     * genBoolValue
     */
    public static function genBoolValue(bool $bool):Value
    {
        $Value                  = new Value();
        $Value->setBoolValue($bool);
        return $Value;
    }

    /**
     * @return Value
     * genNullValue
     */
    public static function genNullValue():Value
    {
        $Value                  = new Value();
        $Value->setNullValue(NullValue::NULL_VALUE);
        return $Value;
    }

    /**
     * @param array $dataList
     * @param bool $strict
     * @param bool $isFail
     * @return Value
     * genArrayValue
     */
    public static function genArrayValue(array $dataList, bool $strict = false, bool &$isFail = false):Value
    {
        if(CommValid::isArrayList($dataList)){
            return self::genListArrayValue($dataList, $strict, $isFail);
        }else{
            return self::genObjectArrayValue($dataList, $strict, $isFail);
        }
    }

    /**
     * @param array $dataList
     * @param bool $strict
     * @param bool $isFail
     * @return Value
     * genListArrayValue
     */
    private static function genListArrayValue(array $dataList, bool $strict = false, bool &$isFail = false):Value
    {
        $isFail                 = false;
        $Value                  = new Value();
        if(count($dataList) < 1 || !CommValid::isArrayList($dataList)){
            $isFail             = true;
            return $Value;
        }
        $ValueItemList          = [];
        foreach ($dataList as $dataVal){
            $isFailItem         = false;
            $ValueItem          = self::genVarValue($dataVal, $strict, $isFailItem);
            if($isFailItem){
                if(!$strict){
                    $isFail     = true;
                    return $Value;
                }else{
                    continue;
                }
            }
            $ValueItemList[]    = $ValueItem;
        }
        if(count($ValueItemList) < 1){
            $isFail             = true;
            return $Value;
        }
        $ListValue              = new ListValue();
        $ListValue->setValues($ValueItemList);
        $Value->setListValue($ListValue);
        return $Value;
    }

    /**
     * @param array $dataList
     * @param bool $strict
     * @param bool $isFail
     * @return Value
     * genObjectArrayValue
     */
    private static function genObjectArrayValue(array $dataList, bool $strict = false, bool &$isFail = false):Value
    {
        $isFail                 = false;
        $Value                  = new Value();
        if(count($dataList) < 1 || !CommValid::isArrayObject($dataList)){
            $isFail             = true;
            return $Value;
        }
        $ValueItemList          = [];
        foreach ($dataList as $dataKey => $dataVal){
            $isFailItem         = false;
            $ValueItem          = self::genVarValue($dataVal, $strict, $isFailItem);
            if($isFailItem){
                if(!$strict){
                    $isFail     = true;
                    return $Value;
                }else{
                    continue;
                }
            }
            $ValueItemList[$dataKey] = $ValueItem;
        }
        if(count($ValueItemList) < 1){
            $isFail             = true;
            return $Value;
        }
        $Struct                 = new Struct();
        $Struct->setFields($ValueItemList);
        $Value->setStructValue($Struct);
        return $Value;
    }

    /**
     * @param $var
     * @param bool $strict
     * @param bool $isFail
     * @return Value
     * genVarValue
     */
    public static function genVarValue($var, bool $strict = false, bool &$isFail = false):Value
    {
        $isFail                 = false;
        if(is_string($var)){
            $Value              = self::genStringValue($var);
        }else if(is_int($var)){
            $Value              = self::genNumberIntValue($var);
        }else if(is_float($var)){
            $Value              = self::genNumberFloatValue($var);
        }else if(is_bool($var)){
            $Value              = self::genBoolValue($var);
        }else if(is_null($var)){
            $Value              = self::genNullValue();
        }else if(is_array($var)){
            $Value              = self::genArrayValue($var, $strict, $isFail);
        }else{
            $Value              = new Value();
            $isFail             = true;
        }
        return $Value;
    }
}